package ssq.utils.wolfmankill;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.Point;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.WindowConstants;

import net.sf.json.JSONObject;
import ssq.utils.wolfmankill.Participant.Status;

public class ClientGUI extends JFrame
{
    public static final Font    SongFont         = new Font("宋体", Font.PLAIN, 21);
    private static final long   serialVersionUID = 1;
    private LinkedList<JButton> participants     = new LinkedList<JButton>();
    private JLabel              statusLabel      = new JLabel("等待连接");
    private JPanel              playerListPane   = new JPanel(new GridLayout(4, 4, 160, 160)), optionsPanel = new JPanel(new BorderLayout()), messagePanel = new JPanel(new GridBagLayout());
    private JTextArea           chatContents     = new JTextArea(3, 20), history = new JTextArea(30, 50);
    private JButton             sendButton       = new JButton("发送"), connectButton = new JButton("连接");
    private JComboBox<String>   nameBox          = new JComboBox<String>();
    private JTextField          addressField     = new JTextField(), portField = new JTextField(3);
    WSClient                    client;
    LinkedList<String>          names            = new LinkedList<String>();
    
    public JTextArea getChatContents()
    {
        return chatContents;
    }
    
    public void setChatContents(JTextArea chatContents)
    {
        this.chatContents = chatContents;
    }
    
    public JTextArea getHistory()
    {
        return history;
    }
    
    public void setHistory(JTextArea history)
    {
        this.history = history;
    }
    
    public JTextField getAddressField()
    {
        return addressField;
    }
    
    public void setAddressField(JTextField addressField)
    {
        this.addressField = addressField;
    }
    
    public List<String> getNames()
    {
        return names;
    }
    
    public void setNames(List<String> names)
    {
        this.names = new LinkedList<>(names);
        resetPlayers();
    }
    
    public JComboBox<String> getNameBox()
    {
        return nameBox;
    }
    
    private void iniView()
    {
        setLayout(new BorderLayout());
        setLocation(100, 100);
        
        GridBagConstraints constraints = new GridBagConstraints();
        constraints.weightx = 1;
        constraints.weighty = 1;
        constraints.fill = GridBagConstraints.BOTH;
        constraints.anchor = GridBagConstraints.WEST;
        constraints.insets = new Insets(1, 1, 1, 1);
        constraints.ipadx = 3;
        constraints.ipady = 3;
        
        constraints.gridheight = 2;
        constraints.gridx = 0;
        chatContents.setAutoscrolls(true);
        chatContents.setFont(SongFont);
        messagePanel.add(new JScrollPane(chatContents), constraints);
        
        constraints.weightx = 0;
        constraints.fill = GridBagConstraints.NONE;
        constraints.gridheight = 1;
        constraints.gridx = 1;
        constraints.gridy = 0;
        messagePanel.add(nameBox, constraints);
        constraints.gridy = 1;
        messagePanel.add(sendButton, constraints);
        
        JPanel addressPanel = new JPanel(new FlowLayout());
        JLabel label = new JLabel("服务器地址: ");
        label.setFont(SongFont);
        addressField.setFont(SongFont);
        portField.setFont(SongFont);
        connectButton.setFont(SongFont);
        addressField.setText("ws://localhost");
        portField.setText("444");
        addressPanel.add(label);
        addressPanel.add(addressField);
        addressPanel.add(portField);
        addressPanel.add(connectButton);
        optionsPanel.add(addressPanel, BorderLayout.NORTH);
        optionsPanel.add(new JScrollPane(playerListPane), BorderLayout.CENTER);
        optionsPanel.add(messagePanel, BorderLayout.SOUTH);
        
        nameBox.setFont(SongFont);
        resetPlayers();
        
        add(optionsPanel, BorderLayout.CENTER);
        statusLabel.setFont(SongFont);
        add(statusLabel, BorderLayout.SOUTH);
        add(new JScrollPane(history), BorderLayout.EAST);
        history.setEditable(false);
        history.setFont(SongFont);
        pack();
    }
    
    static private ClientGUI instance = new ClientGUI();
    
    public static ClientGUI getInstance()
    {
        return instance;
    }
    
    private ClientGUI()
    {
        iniView();
        iniListeners();
        disableOption();
    }
    
    class MyMouseAdapter extends MouseAdapter
    {
        String helper;
        
        MyMouseAdapter(String helper)
        {
            this.helper = helper;
        }
        
        @Override
        public void mouseExited(MouseEvent e)
        {
            refreshState();
        }
        
        @Override
        public void mouseEntered(MouseEvent e)
        {
            statusLabel.setText(helper);
        }
    }
    
    protected void disableReconnect()
    {
        setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
        connectButton.setVisible(false);
    }
    
    protected void enableReconnect()
    {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        connectButton.setVisible(true);
    }
    
    private void disableOption()
    {
        nameBox.setEnabled(false);
        sendButton.setEnabled(false);
        sendButton.removeMouseListener(sendAdapter);
        chatContents.removeKeyListener(sendShortcut);
        
        for (JButton button : participants)
        {
            button.setEnabled(false);
        }
    }
    
    public void connect()
    {
        if (client != null && client.isOpen())
        {
            client.close();
        }
        
        try
        {
            String name = JOptionPane.showInputDialog("设置名字");
            while (name == null || name.trim().length() == 0)
            {
                name = JOptionPane.showInputDialog("重新设置名字");
            }

            setTitle(name);
            client = new WSClient(new URI(addressField.getText() + ":" + portField.getText()), name);
            client.connect();
        }
        catch (URISyntaxException e1)
        {
            history.append("连接的格式不正确 : \n" + addressField.getText() + ":" + portField.getText());
        }
    }
    
    MyMouseAdapter connectMouseAdapter = new MyMouseAdapter("连接到指定服务器")
    {
        @Override
        public void mouseClicked(MouseEvent e)
        {
            connect();
        }

    },
    sendAdapter = new MyMouseAdapter("给指定的玩家发送消息")
    {
        @Override
        public void mouseClicked(MouseEvent e)
        {
            sendMessage();
        };
    };

    KeyListener    connectKeyAdapter   = new KeyAdapter()
    {
        @Override
        public void keyPressed(KeyEvent e)
        {
            if (e.getKeyCode() == KeyEvent.VK_ENTER)
            {
                connect();
            }
        };
    };
    KeyAdapter     sendShortcut        = new KeyAdapter()
    {
        @Override
        public void keyPressed(KeyEvent e)
        {
            if (e.isControlDown() && e.getKeyCode() == KeyEvent.VK_ENTER)
            {
                sendMessage();
            }
        }
    };
    
    String constructMsg(String msg, String from, String to)
    {
        JSONObject tmp = JSONObject.fromObject(WSServer.constructMsg(msg, from));
        tmp.put("to", to);
        return tmp.toString();
    }
    
    private void iniListeners()
    {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        
        connectButton.addMouseListener(connectMouseAdapter);
        addressField.addKeyListener(connectKeyAdapter);
        portField.addKeyListener(connectKeyAdapter);
        chatContents.addKeyListener(sendShortcut);
    }
    
    private void sendMessage()
    {
        if (client != null && client.isOpen())
        {
            String str = chatContents.getText();
            
            if (str.isEmpty())
            {
                WSServer.sleepAWhile();
                return;
            }
            
            JSONObject msg = new JSONObject();
            msg.put("type", "msg");
            msg.put("to", nameBox.getSelectedItem().toString());
            msg.put("msg", str);

            client.send(msg.toString());
            
            chatContents.setText("");
        }
    }
    
    public static void main(String[] args) throws InterruptedException
    {
        getInstance().show();
    }
    
    public void appendMessage(String msg)
    {
        history.append(msg + '\n');
        history.setCaretPosition(history.getText().length());
    }
    
    public void resetPlayers()
    {
        playerListPane.removeAll();
        nameBox.removeAllItems();
        
        nameBox.addItem("all");
        for (String name : names)
        {
            JButton button = new JButton(name);
            button.setText(name);
            button.setBackground(Color.WHITE);
            button.setFont(SongFont);
            button.addMouseListener(participantMouseAdapter);
            participants.add(button);
            nameBox.addItem(name);
            
            playerListPane.add(button);
        }
        nameBox.removeItem("none");
        
        repaint();
    }

    public void refreshState()
    {
        if (client != null && client.me != null)
        {
            statusLabel.setText("身份: " + client.me.role + "  状态: " + client.me.status);
        }
    }
    
    public void reset()
    {
        client.me.forget();
        enableOption();
        names.clear();
        resetPlayers();
        history.setText("");
    }
    
    private void enableOption()
    {
        nameBox.setEnabled(true);
        sendButton.setEnabled(true);
        sendButton.addMouseListener(sendAdapter);
        chatContents.addKeyListener(sendShortcut);
        
        for (JButton button : participants)
        {
            button.setEnabled(true);
        }
    }
    
    public void highlight(String msg)
    {
        for (JButton button : participants)
        {
            String name = button.getText().split("<-")[0];
            button.setText(name);
            button.setBackground(Color.WHITE);
        }

        if (msg != null && !msg.trim().equals(""))
        {
            List<String> entrys = Arrays.asList(msg.split(","));
            
            for (String entry : entrys)
            {
                String[] tmp = entry.split("=");
                
                for (JButton button : participants)
                {
                    String name = button.getText().split("<-")[0];
                    
                    if (name.equals(tmp[1]))
                    {
                        button.setText(button.getText() + "<-" + tmp[0]);
                        button.setBackground(Color.YELLOW);
                    }
                }
            }
        }
        
        repaint();
    }
    
    MyMouseAdapter participantMouseAdapter = new MyMouseAdapter("投他的票或跟他聊天")
                                           {
                                               @Override
                                               public void mouseClicked(MouseEvent e)
                                               {
                                                   JButton button = (JButton) e.getSource();
                                                   if (button.isEnabled() && client.canVote)
                                                   {
                                                       client.send(WSServer.constructMessage("vote", button.getText().split("<-")[0]));
                                                   }
                                                   
                                                   nameBox.setSelectedItem(((JButton) e.getSource()).getText());
                                                   chatContents.requestFocus();
                                               }
                                           };
    
    public void shiver(String msg)
    {
        new Thread()
        {
            @Override
            public void run()
            {
                requestFocus();

                for (int i = 0; i < 3; i++)
                {
                    shiverRound();
                }
            }
        }.start();
        
        appendMessage(msg);
    }
    
    static Point pos[] = new Point[32];
    
    static
    {
        for (int i = 0; i < 32; i++)
        {
            Point tmp = new Point((int) (10 * Math.sin(2 * Math.PI * i / 32)), (int) (10 * Math.cos(2 * Math.PI * i / 32)));
            pos[i] = tmp;
        }
    }
    
    private void shiverRound()
    {
        Point p = getLocation();
        int x = p.x;
        int y = p.y;
        
        for (int i = 0; i < 32; i++)
        {
            try
            {
                Thread.sleep(5);
            }
            catch (InterruptedException e)
            {
            }
            
            setLocation(x + pos[i].x, y + pos[i].y);
        }
        
        setLocation(p);
    }
    
    public void info(String msg)
    {
        JOptionPane.showMessageDialog(this, msg);
    }

    public void disableChat(String msg)
    {
        sendButton.removeMouseListener(sendAdapter);
        chatContents.removeKeyListener(sendShortcut);
    }
    
    public void enableChat()
    {
        sendButton.addMouseListener(sendAdapter);
        chatContents.addKeyListener(sendShortcut);
    }

    public void enable(String msg)
    {
        if (msg.equals("all"))
        {
            enableOption();
        }
        else
        {
            for (JButton button : participants)
            {
                if (msg.contains(button.getText()))
                {
                    button.setEnabled(true);
                }
            }
        }
    }
    
    public void disable(String msg)
    {
        if (msg.equals("all"))
        {
            disableOption();
            client.me.status = Status.dead;
            refreshState();
        }
        else
        {
            for (JButton button : participants)
            {
                if (msg.contains(button.getText()))
                {
                    button.setEnabled(false);
                }
            }
        }
    }
    
    public String toDetailedString()
    {
        try
        {
            StringBuilder sb = new StringBuilder((client == null) ? "" : client.toDetailedString());
            sb.append("\n names: ").append(names.toString());
            return sb.toString();
        }
        catch (Exception e)
        {
            return "";
        }
    }
}
